package com.joelaws.prototype.server;

import gnu.trove.TLongObjectHashMap;

import java.util.Set;

import com.joelaws.prototype.client.meeting.ActionInfo;
import com.joelaws.prototype.client.util.Create;
import com.joelaws.prototype.server.meeting.State;

public class MeetingService {

	private TLongObjectHashMap<Set<State>> stateCache;

	private static MeetingService service;

	private MeetingService() {
		reset();
	}

	public synchronized void reset() {
		stateCache = new TLongObjectHashMap<Set<State>>();
	}

	public static MeetingService getService() {
		if (service == null) {
			synchronized (MeetingService.class) {
				if (service == null) {
					service = new MeetingService();
				}
			}
		}
		return service;
	}

	public synchronized long[] getAllMeetings(long userID) {
		Set<State> userStates = stateCache.get(userID);
		if (userStates == null) {
			return new long[0];
		}
		long[] users = new long[userStates.size()];
		int curr = 0;
		for (State state : userStates) {
			if (state.getUserOne() == userID) {
				users[curr] = state.getUserTwo();
			} else {
				users[curr] = state.getUserOne();
			}
			curr++;
		}
		return users;

	}

	public synchronized ActionInfo[] getNextActions(long userID) {
		Set<State> userStates = stateCache.get(userID);
		if (userStates == null) {
			return null;
		}
		ActionInfo[] actions = new ActionInfo[userStates.size()];
		int curr = 0;
		for (State state : userStates) {
			actions[curr] = new ActionInfo(state.getActionQuestion(userID), state.getActionChoices(userID), state
					.getMeetingType());
			curr++;
		}
		return actions;
	}

	public synchronized ActionInfo getNextAction(long mainUser, long otherUser) {
		State state = getStateIfExists(mainUser, otherUser);

		if (state == null) {
			throw new IllegalArgumentException("No meeting initiated between " + mainUser + " and " + otherUser);
		}

		return new ActionInfo(state.getActionQuestion(mainUser), state.getActionChoices(mainUser), state
				.getMeetingType());
	}

	public synchronized ActionInfo executeAction(long mainUser, long otherUser, String choice) {
		State state = getStateIfExists(mainUser, otherUser);

		if (state == null) {
			throw new IllegalArgumentException("No meeting initiated between " + mainUser + " and " + otherUser);
		}

		state.executeAction(choice, mainUser);

		return new ActionInfo(state.getActionQuestion(mainUser), state.getActionChoices(mainUser), state
				.getMeetingType());
	}

	public synchronized ActionInfo initiateMeeting(long userOne, long userTwo) {
		State state = getStateIfExists(userOne, userTwo);

		if (state == null || state.isCompleted()) {
			state = new State(userOne, userTwo);
			addState(userOne, state);
			addState(userTwo, state);
		}

		return new ActionInfo(state.getActionQuestion(userOne), state.getActionChoices(userOne), state.getMeetingType());
	}

	private void addState(long userID, State state) {
		Set<State> userStates = stateCache.get(userID);
		if (userStates == null) {
			userStates = Create.newSet();
			stateCache.put(userID, userStates);
		}
		userStates.add(state);
	}

	private State getStateIfExists(long userOne, long userTwo) {
		Set<State> userOneStates = stateCache.get(userOne);
		if (userOneStates == null) {
			return null;
		}
		for (State state : userOneStates) {
			if (state.getUserOne() == userTwo || state.getUserTwo() == userTwo) {
				return state;
			}
		}
		return null;
	}
}
